/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Moshe
 */
public class HillClimb {

    private Equation equation;
    private BitVector currVector;
    

    public HillClimb(Equation equation, int bits) {
        this.equation = equation;        
        currVector = new BitVector(bits);        
    }

    public HillClimb(Equation equation, BitVector startVector)
    {
        this.equation = equation;
        currVector = startVector;
    }    

    private BitVector GetNeighbor(int index) throws IllegalAccessException {
        BitVector neighbor = (BitVector) currVector.clone();
        neighbor.switchBit(index);
        return neighbor;
    }

    private TwoReturnValues<BitVector, Integer> GetBestNeighbor() throws IllegalAccessException {
        int maxClause = 0;
        int currClauseCount = 0;
        BitVector currNeighbor = null;
        BitVector bestNeighbor = null;

        for (int i = 0; i < currVector.getBitsNum(); i++) {
            currNeighbor = GetNeighbor(i);
            RandomHillClimb.nodeCount++;
            currNeighbor.calcFitness();
            currClauseCount = currNeighbor.getFitness();
            if (currClauseCount > maxClause) {
                maxClause = currClauseCount;
                bestNeighbor = currNeighbor;
            }

            if ((RandomHillClimb.nodeCount % 10) == 0) {
                if (maxClause > RandomHillClimb.bestGrade) {
                    RandomHillClimb.bestTime = System.currentTimeMillis() - RandomHillClimb.startTime;
                    RandomHillClimb.bestGrade = maxClause;
                    RandomHillClimb.bestVector = bestNeighbor;
                    RandomHillClimb.bestNodeCount=RandomHillClimb.nodeCount;
                }
               
               RandomHillClimb.UpdateUI();
            }
        }
        
        return new TwoReturnValues(bestNeighbor, maxClause);
    }

    public int Climb() throws IllegalAccessException {
        
        int currClauseCount = currVector.getFitness();
        int lastClauseCount = -1;
        int maxClause = currClauseCount;

        if (RandomHillClimb.nodeCount++ == 0) {
            RandomHillClimb.bestGrade=currClauseCount;
            RandomHillClimb.bestVector=currVector;
            RandomHillClimb.bestNodeCount=RandomHillClimb.nodeCount;
            RandomHillClimb.UpdateUI();
        }
            

        while ((currClauseCount > lastClauseCount) && (maxClause < equation.getClauseSize())) {
            lastClauseCount = currClauseCount;
            TwoReturnValues<BitVector, Integer> currBest = GetBestNeighbor();
            currClauseCount = currBest.second;

            if (currClauseCount > maxClause) {
                maxClause = currClauseCount;
                currVector = currBest.first;
            }
        }

        return maxClause;
    }
}
